App.require(["matrix3"], function (matrix3) {
    var Matrix3 = matrix3.Matrix3;
    App.defineWidget("funnel", {
        _createWidths: function (options, maxWidth, percent) {
            var numList = options.map(function (obj) {
                return parseFloat(obj.value);
            });

            var con = maxWidth / numList[0];
            var calcList = [0];
            for (var i = numList.length - 1; i >= 0; i--) {
                calcList.push(numList[i] * con * percent);
            }
            return calcList;
        },
        _createPointList: function (x, y, cl, pl, distance) {
            return [
                { y: y, x: x - cl / 2 },
                { y: y, x: x + cl / 2 },
                { y: y + distance, x: x - pl / 2 },
                { y: y + distance, x: x + pl / 2 }
            ];
        },
        stepDistance: function (distance) {
            return { x: 0, y: distance };
        },
        _createPoints: function (lens, len, distance) {
            var p = len / distance, result = [], x = 0, y = 0;
            for (var i = 1; i < lens.length; i++) {
                var cl = lens[i - 1], pl = lens[i], pnums = [];
                var plist = this._createPointList(x, y, cl, pl, distance);
                pnums.push(plist[0]);
                pnums.push({ x: (1 - p) * plist[0].x + p * plist[2].x, y: (1 - p) * plist[0].y + p * plist[2].y })
                pnums.push({ x: (1 - p) * plist[1].x + p * plist[3].x, y: (1 - p) * plist[1].y + p * plist[3].y })
                pnums.push(plist[1]);
                var stepObj = this.stepDistance(distance);
                x += stepObj.x;
                y += stepObj.y;
                result.push(pnums);
            }
            return result;
        },
        _createPointsPath: function (ctx, points, ratio) {
            ratio = ratio || 1;
            ctx.beginPath();
            ctx.moveTo(points[0].x * ratio, points[0].y * ratio);
            for (var i = 1; i < points.length; i++) {
                ctx.lineTo(points[i].x * ratio, points[i].y * ratio);
            }
            ctx.closePath();
        },
        render: function (ctx) {
            ctx.save();
            var style = this.style;
            ctx.globalAlpha = style.opacity;
            var shadowObj = App.Widget.strToShadow(style.shadow);
            if (shadowObj) {
                ctx.shadowOffsetX = shadowObj.x;
                ctx.shadowOffsetY = shadowObj.y;
                ctx.shadowBlur = shadowObj.blur;
                ctx.shadowColor = shadowObj.color;
            }
            ctx.translate(style.x, style.y);
            var options = style.option;
            var lens = this._createWidths(options, style.fwidth, style.percent);
            var points = this._createPoints(lens, style.fheight, style.distance);
            if (Array.isArray(style.linedash) && style.linedash.length > 0) {
                ctx.setLineDash(style.linedash);
                ctx.lineDashOffset = style.linedashoffset;
                ctx.linewidth = style.linewidth;
            }
            for (var i = 0; i < points.length; i++) {
                var obj = this.style.option[i];
                ctx.save();
                this._createPointsPath(ctx, points[i]);
                var fillStyle = obj.fill || style.fill,
                    strokeStyle = obj.stroke || style.stroke;

                if (fillStyle) {
                    ctx.fillStyle = fillStyle;
                    ctx.fill();
                }
                if (strokeStyle) {
                    ctx.strokeStyle = strokeStyle;
                    ctx.stroke();
                }
                ctx.restore();
            }
            ctx.restore();
        },
        createPath: function (ctx) {
            var style = this.style, options = style.option;
            var lens = this._createWidths(options, style.fwidth, style.percent);
            var points = this._createPoints(lens, style.fheight, style.distance);

            ctx.beginPath();
            for (var i = 0; i < points.length; i++) {
                var ps = points[i];
                ctx.moveTo(ps[0].x, ps[0].y);
                for (var j = 1; j < ps.length; j++) {
                    ctx.lineTo(ps[j].x, ps[j].y);
                }
                ctx.closePath();
            }
        },
        isPointIn: function (ctx, x, y) {
            var style = this.style;
            ctx.save();
            ctx.translate(style.x, style.y);
            this.createPath(ctx);
            var isIn = ctx.isPointInPath(x, y);
            ctx.restore();
            return isIn;
        },
        style: {
            x: 0,
            y: 0,
            shadow: "0 0 0 black",
            fwidth: 80,
            fheight: 30,
            distance: 35,
            percent: 1,
            fill: "red",
            stroke: "black",
            linewidth: 1,
            linedash: "",
            linedashoffset: 0,
            direction: App.AxisDirectionOption.BOTTOMTOP,
            opacity: 1,
            option: [ { value: 40 }, { value: 80 } ]
        },
        get x() {
            return this.style.x;
        },
        set x(val) {
            this.style.x = val;
            this.getScene().nextRender();
        },
        set y(val) {
            this.style.y = val;
            this.getScene().nextRender();
        },
        get y() {
            return this.style.y;
        },
        get direction() {
            return this.style.direction;
        },
        set direction(val) {
            this.style.direction = val;
            this.getScene().nextRender();
        },
        set shadow(val) {
            this.style.shadow = val;
            this.getScene().nextRender();
        },
        get shadow() {
            return this.style.shadow;
        },
        get fwidth() { 
            return this.style.fwidth;
        },
        set fwidth(val) { 
            this.style.fwidth = val;
            this.getScene().nextRender();
        },
        get fheight() { 
            return this.style.fheight;
        },
        set fheight(val) {
            this.style.fheight = val;
            this.getScene().nextRender();
         },
        get distance() { 
            return this.style.distance;
        },
        set distance(val) { 
            this.style.distance = val;
            this.getScene().nextRender();
        },
        get stroke() {
            return this.style.stroke;
        },
        set stroke(val) {
            this.style.stroke = val;
            this.getScene().nextRender();
        },
        get fill() {
            return this.style.fill;
        },
        set fill(val) {
            this.style.fill = val;
            this.getScene().nextRender();
        },
        get opacity() {
            return this.style.opacity;
        },
        set opacity(val) {
            this.style.opacity = val;
            this.getScene().nextRender();
        },
        get percent() { 
            return this.style.percent;
        },
        set percent(val) { 
            this.style.percent = val;
            this.getScene().nextRender();
        },
        get linewidth() {
            return this.style.linewidth;
        },
        set linewidth(val) {
            this.style.linewidth = val;
            this.getScene().nextRender();
        },
        get linedash() {
            return this.style.linedash;
        },
        set linedash(val) {
            this.style.linedash = val;
            this.getScene().nextRender();
        },
        get linedashoffset() {
            return this.style.linedashoffset;
        },
        set linedashoffset(val) {
            this.style.linedashoffset = val;
            this.getScene().nextRender();
        }
    })
})